package org.tamal.servlet;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.tamal.Constants;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

/**
 * Email browser statistics periodically as a cron job.
 * @author Tamal Kanti Nath
 */
public class BrowserStatistics extends HttpServlet {

    private static final long serialVersionUID = 4018314456512760775L;
    private final Logger log = Logger.getLogger(getClass().getName());
    private static final DatastoreService ds = DatastoreServiceFactory.getDatastoreService();

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        Entity entity = createDifferentialStatistics();
        emailBrowserStatistics(entity);
    }

    private static Entity createDifferentialStatistics() {
        String date = new SimpleDateFormat(Constants.DATE_FORMAT_ISO).format(new Date());
        Key key = KeyFactory.createKey(Constants.USER_AGENT, date);
        Entity today, current, total;
        try {
            today = ds.get(key);
        } catch (EntityNotFoundException e) {
            today = new Entity(key);
        }
        key = KeyFactory.createKey(Constants.USER_AGENT, Constants.TOTAL);
        try {
            total = ds.get(key);
        } catch (EntityNotFoundException e) {
            total = new Entity(key);
        }
        key = KeyFactory.createKey(Constants.USER_AGENT, Constants.CURRENT);
        try {
            current = ds.get(key);
        } catch (EntityNotFoundException e) {
            current = new Entity(key);
        }
        Long count, c;
        for (Map.Entry<String, Object> entry : current.getProperties().entrySet()) {
            String userAgent = entry.getKey();
            c = (Long) entry.getValue();

            count = (Long) total.getProperty(userAgent);
            count = (count == null) ? c : count + c;
            total.setProperty(userAgent, count);

            count = (Long) today.getProperty(userAgent);
            count = (count == null) ? c : count + c;
            today.setProperty(userAgent, count);
        }
        ds.put(total);
        ds.put(today);
        ds.delete(key);
        return today;
    }

    private void emailBrowserStatistics(Entity entity) throws UnsupportedEncodingException {
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);
        Message mail = new MimeMessage(session);
        InternetAddress address = new InternetAddress("browser@tamalnath.appspotmail.com", "Browser Statistics");
        try {
            mail.setFrom(address);
            mail.addRecipient(RecipientType.TO, address);
            mail.setSubject("Browser statistics for " + entity.getKey().getName());
            mail.setText(getBrowserStatistics(entity));
            Transport.send(mail);
        } catch (MessagingException e) {
            log.throwing(getClass().getName(), "doGet", e);
        }
    }

    private static String getBrowserStatistics(Entity entity) {
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : entity.getProperties().entrySet()) {
        	sb.append(entry.getKey() + ": " + entry.getValue() + "\n");
        }
        return sb.toString();
    }

    /**
     * Returns a date string. The date depends on the delta i.e. -1 represents
     * yesterday, 0 is today, 1 is tomorrow etc.
     * @param delta the shift factor
     * @return date string
     */
    public static String getDateString(int delta) {
        DateFormat df = new SimpleDateFormat(Constants.DATE_FORMAT_ISO);
        Calendar cal = df.getCalendar();
        cal.add(Calendar.DATE, delta);
        return df.format(cal.getTime());
    }
}
